package matheus.tp01cg.objetosdedesenho.recorte;

import java.util.ArrayList;

import matheus.tp01cg.objetosdedesenho.Coords;
import matheus.tp01cg.objetosdedesenho.Poligono;
import android.util.Log;

public final class SutherlandHodgman {

	private static final int SUPERIOR = 0;
	private static final int DIREITA = 1;
	private static final int INFERIOR = 2;
	private static final int ESQUERDA = 3;

	private static boolean interior(Coords ponto, int fronteira, int lado) {
		boolean ret = false;
		switch (lado) {
		case SUPERIOR:
			ret = ponto.y > fronteira;
			break;
		case DIREITA:
			ret = ponto.x < fronteira;
			break;
		case INFERIOR:
			ret = ponto.y < fronteira;
			break;
		case ESQUERDA:
			ret = ponto.x > fronteira;
			break;
		}
		return ret;
	}

	private static Coords intersecao(Coords pontoA, Coords pontoB,
			int fronteira, int lado) {
		int x1, y1, x2, y2;
		x1 = pontoA.x;
		y1 = pontoA.y;
		x2 = pontoB.x;
		y2 = pontoB.y;
		int xInt = 0, yInt = 0;
		double a = (double) (y2 - y1) / (double) (x2 - x1);
		double b = (double) y1
				- (((double) (y2 - y1) / (double) (x2 - x1)) * (double) x1);

		switch (lado) {
		case SUPERIOR:
			yInt = fronteira;
			xInt = (int) Math.round((yInt - b) / a);
			//Log.v(null, "a SUPERIOR: " + a);
			if (Double.isNaN(a) || Double.isInfinite(a)) { // nao ha variacao em x
				xInt = x1;
			}
			break;
		case DIREITA:
			xInt = fronteira;
			yInt = (int) Math.round(a * xInt + b);
			//Log.v(null, "a DIREITA: " + a);
			break;
		case INFERIOR:
			yInt = fronteira;
			xInt = (int) Math.round((yInt - b) / a);
			//Log.v(null, "a INFERIOR: " + a);
			if (Double.isNaN(a) || Double.isInfinite(a)) { // nao ha variacao em x
				xInt = x1;
			}
			break;
		case ESQUERDA:
			xInt = fronteira;
			yInt = (int) Math.round(a * xInt + b);
			//Log.v(null, "a ESQUERDA: " + a);
			break;
		}

		return new Coords(xInt, yInt);
	}

	@SuppressWarnings("unchecked")
	static Poligono recortaPoligono(Poligono poligono, Coords limMin,
			Coords limMax) {
		Poligono novoPoligono = null;
		try {
			novoPoligono = (Poligono) poligono.clone();
			ArrayList<Coords> vertices = novoPoligono.listaDeVertices;
			ArrayList<Coords> novaLista = new ArrayList<Coords>();

			int[] fronteiras = new int[4];
			fronteiras[0] = limMin.y;
			fronteiras[1] = limMax.x;
			fronteiras[2] = limMax.y;
			fronteiras[3] = limMin.x;
			for (int lado = 0; lado < 4; lado++) {
				novaLista.clear();
				Coords vAnt = vertices.get(vertices.size() - 1);
				for (int i = 0; i < vertices.size(); i++) {
					if (interior(vertices.get(i), fronteiras[lado], lado)) {
						if (!interior(vAnt, fronteiras[lado], lado)) {
							Coords vInt = intersecao(vAnt, vertices.get(i),
									fronteiras[lado], lado);
							novaLista.add(vInt);
						}
						novaLista.add(vertices.get(i));
					} else {
						if (interior(vAnt, fronteiras[lado], lado)) {
							Coords vInt = intersecao(vAnt, vertices.get(i),
									fronteiras[lado], lado);
							novaLista.add(vInt);
						}
					}
					vAnt = vertices.get(i);
				}
				vertices = (ArrayList<Coords>) novaLista.clone();
			}

			novoPoligono.listaDeVertices = vertices;
			novoPoligono.fechar();
		} catch (CloneNotSupportedException e) {
			Log.d(null,
					e.getClass() + " : SutherlandHodgman.recortaPoligono()", e);
		} catch (Exception e) {
			Log.d(null,
					e.getClass() + " : SutherlandHodgman.recortaPoligono()", e);

		}
		return novoPoligono;
	}
}
